/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2021 Huawei Technologies Co., Ltd */

#ifndef HINIC3_CMDQ_H
#define HINIC3_CMDQ_H

#include <linux/types.h>
#include <linux/completion.h>
#include <linux/spinlock.h>

#include "mpu_inband_cmd_defs.h"
#include "hinic3_hw.h"
#include "hinic3_wq.h"
#include "hinic3_common.h"
#include "hinic3_hwdev.h"

struct dma_pool {
	unsigned int size; /* 每个块的大小（字节），用于小块DMA内存池 */
	void *dev_hdl; /* 设备句柄/上下文，用于与PCI/设备关联 */
};

#define HINIC3_SCMD_DATA_LEN		16 /* 同步命令内联数据最大长度（字节） */

#define	HINIC3_CMDQ_DEPTH		4096 /* 每个CMDQ队列的WQE深度 */

enum hinic3_cmdq_type {
	HINIC3_CMDQ_SYNC,  /* 同步命令队列（等待完成） */
	HINIC3_CMDQ_ASYNC, /* 异步命令队列（回调或轮询完成） */
	HINIC3_MAX_CMDQ_TYPES = 4 /* 最大支持的CMDQ类型数（包含预留） */
};

enum hinic3_db_src_type {
	HINIC3_DB_SRC_CMDQ_TYPE,   /* 门铃来源：命令队列 */
	HINIC3_DB_SRC_L2NIC_SQ_TYPE, /* 门铃来源：L2 NIC发送队列 */
};

enum hinic3_cmdq_db_type {
	HINIC3_DB_SQ_RQ_TYPE, /* 通用SQ/RQ类型门铃格式 */
	HINIC3_DB_CMDQ_TYPE,  /* CMDQ专用门铃格式 */
};

/* hardware define: cmdq wqe */
struct hinic3_cmdq_header {
	u32	header_info; /* 头部信息：模块/命令/通道等编码 */
	u32	saved_data;  /* 由硬件回写或软件保留的附加信息 */
};

struct hinic3_scmd_bufdesc {
	u32	buf_len; /* 有效数据长度（字节） */
	u32	rsvd;    /* 保留 */
	u8	data[HINIC3_SCMD_DATA_LEN]; /* 内联数据缓冲（小数据场景） */
};

struct hinic3_lcmd_bufdesc {
	struct hinic3_sge	sge; /* 大数据时使用SGE（DMA地址+长度） */
	u32			rsvd1; /* 保留 */
	u64			saved_async_buf; /* 异步场景的buf地址/标识保存 */
	u64			rsvd3; /* 保留 */
};

struct hinic3_cmdq_db {
	u32	db_head; /* 生产者索引/头指针 */
	u32	db_info; /* 门铃控制信息（队列类型/通道等） */
};

struct hinic3_status {
	u32	status_info; /* 状态字段：完成码/错误码等 */
};

struct hinic3_ctrl {
	u32	ctrl_info; /* 控制字段：方向/数据类型/标志位等 */
};

struct hinic3_sge_resp {
	struct hinic3_sge sge; /* 硬件回写的响应数据SGE */
	u32		rsvd; /* 保留 */
};

struct hinic3_cmdq_completion {
	union {
	struct hinic3_sge_resp	sge_resp;   /* 通过SGE返回响应（长响应） */
	u64			direct_resp; /* 直接回写响应（短响应） */
	};
};

struct hinic3_cmdq_wqe_scmd {
	struct hinic3_cmdq_header	header; /* WQE头：命令基本信息 */
	u64				rsvd;   /* 对齐/保留 */
	struct hinic3_status		status; /* 完成状态/错误码 */
	struct hinic3_ctrl		ctrl;   /* 控制信息 */
	struct hinic3_cmdq_completion	completion; /* 响应区（直接/SGE） */
	struct hinic3_scmd_bufdesc	buf_desc; /* 内联小数据描述符 */
};

struct hinic3_cmdq_wqe_lcmd {
	struct hinic3_cmdq_header	header; /* WQE头：命令基本信息 */
	struct hinic3_status		status; /* 完成状态/错误码 */
	struct hinic3_ctrl		ctrl;   /* 控制信息 */
	struct hinic3_cmdq_completion	completion; /* 响应区（直接/SGE） */
	struct hinic3_lcmd_bufdesc	buf_desc; /* 大数据（SGE方式）描述符 */
};

struct hinic3_cmdq_inline_wqe {
	struct hinic3_cmdq_wqe_scmd	wqe_scmd; /* 内联WQE（小数据） */
};

struct hinic3_cmdq_wqe {
	union {
	struct hinic3_cmdq_inline_wqe	inline_wqe; /* 内联小数据命令 */
	struct hinic3_cmdq_wqe_lcmd	wqe_lcmd;  /* 大数据命令（SGE） */
	};
};

struct hinic3_cmdq_arm_bit {
	u32	q_type; /* 队列类型（如CEQ/AEQ/CMDQ等） */
	u32	q_id;   /* 队列编号 */
};

enum hinic3_cmdq_status {
	HINIC3_CMDQ_ENABLE = BIT(0), /* CMDQ已使能标志 */
};

enum hinic3_cmdq_cmd_type {
	HINIC3_CMD_TYPE_NONE,        /* 无效/未设置 */
	HINIC3_CMD_TYPE_SET_ARM,     /* 设置ARM（中断/事件使能） */
	HINIC3_CMD_TYPE_DIRECT_RESP, /* 期望直接回写响应 */
	HINIC3_CMD_TYPE_SGE_RESP,    /* 期望通过SGE返回响应 */
	HINIC3_CMD_TYPE_ASYNC,       /* 异步命令 */
	HINIC3_CMD_TYPE_FAKE_TIMEOUT,/* 伪超时（测试/容错） */
	HINIC3_CMD_TYPE_TIMEOUT,     /* 真正超时 */
	HINIC3_CMD_TYPE_FORCE_STOP,  /* 强制停止命令执行 */
};

struct hinic3_cmdq_cmd_info {
	enum hinic3_cmdq_cmd_type	cmd_type;   /* 命令类型（响应形式/同步异步） */
	u16				channel;    /* 逻辑通道/队列号 */
	u16				rsvd1;      /* 保留 */

	struct completion		*done;       /* 同步命令完成量指针 */
	int				*errcode;    /* 错误码输出地址 */
	int				*cmpt_code;  /* 完成码输出地址 */
	u64				*direct_resp;/* 直接响应数据输出地址 */
	u64				cmdq_msg_id; /* 消息唯一标识/序列号 */

	struct hinic3_cmd_buf		*buf_in;    /* 输入数据缓冲 */
	struct hinic3_cmd_buf		*buf_out;   /* 输出数据缓冲（可选） */
};

struct hinic3_cmdq {
	struct hinic3_wq		wq;        /* 命令队列的软件WQ（环） */

	enum hinic3_cmdq_type		cmdq_type; /* 队列类型：同步/异步 */
	int				wrapped;   /* 生产者索引是否回环标志 */

	/* 发送CMDQ命令时的保护锁 */
	spinlock_t			cmdq_lock; /* 防止并发发送/竞态 */

	struct cmdq_ctxt_info		cmdq_ctxt; /* 硬件上下文（门铃/基址） */

	struct hinic3_cmdq_cmd_info	*cmd_infos; /* 每个WQE对应的命令跟踪信息 */

	struct hinic3_hwdev		*hwdev;    /* 硬件设备抽象 */
	u64				rsvd1[2];   /* 保留 */
};

struct hinic3_cmdqs {
	struct hinic3_hwdev		*hwdev;         /* 设备抽象指针 */

	struct pci_pool		*cmd_buf_pool;   /* 小块一致性DMA内存池（命令缓冲） */
	u8 __iomem			*cmdqs_db_base;   /* CMDQ门铃基地址（MMIO） */

	/* VF场景下所有CMDQ的CLA在1级CLA时占用1个PAGE */
	dma_addr_t			wq_block_paddr;  /* WQ块物理地址 */
	void				*wq_block_vaddr;  /* WQ块虚拟地址 */
	struct hinic3_cmdq		cmdq[HINIC3_MAX_CMDQ_TYPES]; /* 各类型CMDQ实例 */

	u32				status;        /* 状态位（如使能） */
	u32				disable_flag;  /* 关闭标记（调试/容错） */

	bool				lock_channel_en; /* 是否启用通道锁 */
	unsigned long			channel_stop;   /* 通道停止位图（每通道一位） */
	u8				cmdq_num;      /* 实际CMDQ数量 */
	u32				rsvd1;         /* 保留 */
	u64				rsvd2;         /* 保留 */
};

void hinic3_cmdq_ceq_handler(void *handle, u32 ceqe_data); /* CEQ事件处理（CMDQ完成） */

int hinic3_reinit_cmdq_ctxts(struct hinic3_hwdev *hwdev); /* 重新初始化CMDQ上下文（热复位后） */

bool hinic3_cmdq_idle(struct hinic3_cmdq *cmdq); /* 判断CMDQ是否空闲 */

int hinic3_cmdqs_init(struct hinic3_hwdev *hwdev); /* 初始化所有CMDQ资源 */

void hinic3_cmdqs_free(struct hinic3_hwdev *hwdev); /* 释放所有CMDQ资源 */

void hinic3_cmdq_flush_cmd(struct hinic3_hwdev *hwdev,
			   struct hinic3_cmdq *cmdq); /* 刷新并结束挂起命令（错误恢复） */

int hinic3_cmdq_set_channel_status(struct hinic3_hwdev *hwdev, u16 channel,
				   bool enable); /* 使能/关闭指定通道 */

void hinic3_cmdq_enable_channel_lock(struct hinic3_hwdev *hwdev, bool enable); /* 开关通道级锁保护 */

void hinic3_cmdq_flush_sync_cmd(struct hinic3_hwdev *hwdev); /* 刷掉所有同步命令（等待队列清空） */

#endif

